home *** CD-ROM | disk | FTP | other *** search
/ BCI NET / BCI NET Dec 94.iso / archives / networking / amitcp / wu-ftpd-37.19.lha / wu-ftpd / src / amiga.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-17  |  13.3 KB  |  677 lines

  1. /*
  2.  * Amiga support routines for chroot() emulation,
  3.  * some MultiUser support routines, alarm() and
  4.  * setproctitle().
  5.  *
  6.  * © 1994 Blaz Zupan, <blaz.zupan@uni-mb.si>
  7.  * All Rights Reserved
  8.  *
  9.  */
  10.  
  11. #include <exec/memory.h>
  12. #include <devices/timer.h>
  13. #include <libraries/multiuser.h>
  14. #include <proto/multiuser.h>
  15. #include <proto/dos.h>
  16. #include <proto/exec.h>
  17. #include <proto/usergroup.h>
  18. #include <string.h>
  19. #include <stdio.h>
  20. #include <stdarg.h>
  21. #include <signal.h>
  22. #include "extensions.h"
  23. #include "config.h"
  24.  
  25. extern char *amigausername;
  26. extern struct muBase *muBase;
  27.  
  28. /*
  29.  * This routine is an attempt to emulate the Unix chroot()
  30.  * function. It only saves the name supplied in the global
  31.  * AmigaRootDir. Everything else must be done by CheckAccess().
  32.  */
  33. extern int anonymous, guest;
  34. char AmigaRootDir[MAXPATHLEN + 2] = "";
  35.  
  36. int
  37. chroot (char *dir)
  38. {
  39.   BPTR lock;
  40.  
  41.   if (lock = Lock (dir, SHARED_LOCK))
  42.   {
  43.     NameFromLock (lock, AmigaRootDir, MAXPATHLEN);
  44.     UnLock (lock);
  45.     return 0;
  46.   }
  47.   return -1;
  48. }
  49.  
  50. /*
  51.  * Checks if pathname "name1" is above
  52.  * "name" in directory structure.
  53.  */
  54. static BOOL
  55. IsParent (char *name1, char *name2)
  56. {
  57.   BOOL ret = 0;
  58.   BPTR l1;
  59.  
  60.   if (l1 = Lock (name1, SHARED_LOCK))
  61.   {
  62.     BPTR l2;
  63.  
  64.     if (l2 = Lock (name2, SHARED_LOCK))
  65.     {
  66.       switch (SameLock (l1, l2))
  67.       {
  68.       case LOCK_DIFFERENT:
  69.     break;
  70.       case LOCK_SAME:
  71.     ret = 2;
  72.     break;
  73.       case LOCK_SAME_VOLUME:
  74.     {
  75.       BPTR l;
  76.  
  77.       while (l2)
  78.       {
  79.         l = l2;
  80.         l2 = ParentDir (l);
  81.         UnLock (l);
  82.         if (SameLock (l1, l2) == LOCK_SAME)
  83.         {
  84.           ret = 1;
  85.           break;
  86.         }
  87.       }
  88.       break;
  89.     }
  90.       }
  91.       UnLock (l2);
  92.     }
  93.     UnLock (l1);
  94.   }
  95.   return ret;
  96. }
  97.  
  98. /* Compare two strings with pattern matching */
  99. static BOOL
  100. mymatch (char *pattern, char *string)
  101. {
  102.   BOOL ret = FALSE;
  103.   char *parsedpattern;
  104.   long len = strlen (pattern) * 2 + 10;
  105.   long oldflags = DOSBase->dl_Root->rn_Flags;
  106.  
  107.   DOSBase->dl_Root->rn_Flags |= RNF_WILDSTAR;    /* turn on recognitions of star as wildcard */
  108.   if (parsedpattern = malloc (len))
  109.   {
  110.     if (ParsePattern (pattern, parsedpattern, len) != -1)
  111.       ret = MatchPattern (parsedpattern, string);
  112.     free (parsedpattern);
  113.   }
  114.   DOSBase->dl_Root->rn_Flags = oldflags;    /* restore original flags */
  115.   return ret;
  116. }
  117.  
  118. /* Checks if user is allowed to access file/directory.
  119.  * If create == TRUE check for parent of specified name
  120.  * (this is used if we want to check if user is allowed
  121.  * to access the directory into which a file should be
  122.  * created - so now "put <something> AmiTCP:db/passwd"
  123.  * hacks are possible).
  124.  */
  125. BOOL
  126. CheckAccess (char *dir, BOOL create)
  127. {
  128.   BPTR lock;
  129.   char name[MAXPATHLEN];
  130.   struct aclmember *entry = NULL;
  131.  
  132.   strcpy (name, dir);
  133.   lock = Lock (name, SHARED_LOCK);
  134.   if (!lock && create)
  135.   {
  136.     *(FilePart (name)) = 0;
  137.     lock = Lock (name, SHARED_LOCK);
  138.   }
  139.  
  140.   if (lock)
  141.     UnLock (lock);
  142.   else
  143.     /* If we could not access file/directory then return "OK"
  144.      * for now because access will be denied later by the
  145.      * command that called us.
  146.      */
  147.     return TRUE;
  148.  
  149.  
  150.   /* first check if directory is on "deny" list */
  151.   while (getaclentry ("denydir", &entry) && ARG0 && ARG1)
  152.   {
  153.     if (mymatch (ARG1, amigausername) && IsParent (ARG0, name))
  154.       return FALSE;
  155.   }
  156.   /* now see if it is under root dir */
  157.   if (IsParent (AmigaRootDir, name))
  158.     return TRUE;
  159.   /* check if access is allowed even if dir is not under root */
  160.   else
  161.   {
  162.     entry = NULL;
  163.     while (getaclentry ("allowdir", &entry) && ARG0 && ARG1)
  164.     {
  165.       if (mymatch (ARG1, amigausername) && IsParent (ARG0, name))
  166.     return TRUE;
  167.     }
  168.   }
  169.   /* If directory is not on deny or allow list and not
  170.    * under root directory then we allow access for
  171.    * real users and don't allow access for guests.
  172.    */
  173.   if (!anonymous && !guest)
  174.     return TRUE;
  175.   else
  176.     return FALSE;
  177. }
  178.  
  179. /*
  180.  * Simulate Unix geteuid() call with MultiUser.
  181.  */
  182. int
  183. amiga_geteuid (void)
  184. {
  185.   if (muBase)
  186.     return ((muGetTaskOwner (FindTask (NULL)) & muMASK_UID) >> 16);
  187.   else
  188. #undef geteuid
  189.     return (geteuid ());
  190. }
  191.  
  192. /*
  193.  * Simulate Unix seteuid() call with MultiUser.
  194.  * You have to be logged in as root initially for this
  195.  * routine to work (after that it correctly keeps track
  196.  * of the user).
  197.  */
  198. int
  199. amiga_seteuid (int u)
  200. {
  201.   if (muBase)
  202.   {
  203.     ULONG tags[5];
  204.     int res = -1;
  205.  
  206.     if (u == 0)
  207.     {
  208.       int uid;
  209.  
  210.       uid = amiga_geteuid ();
  211.  
  212.       /* Are we already root? */
  213.       if (uid == muROOT_UID)
  214.     return 0;
  215.  
  216.       /* We can't set effective user ID to root
  217.        * if we are currently logged in as nobody
  218.        */
  219.       if (uid == muNOBODY_UID)
  220.     return -1;
  221.  
  222.       /* Now logout until we become either root or
  223.        * nobody. If we become nobody we fail.
  224.        */
  225.       do
  226.       {
  227.     tags[0] = muT_Quiet;
  228.     tags[1] = TRUE;
  229.     tags[2] = TAG_END;
  230.     muLogoutA (tags);
  231.     uid = amiga_geteuid ();
  232.       }
  233.       while (uid != muROOT_UID && uid != muNOBODY_UID);
  234.  
  235.       return ((uid == muROOT_UID) ? 0 : -1);
  236.     }
  237.  
  238.     /* Check if we are maybe already logged in as that user. */
  239.     if (u == amiga_geteuid ())
  240.       return 0;
  241.  
  242.     /* Ok, so we are trying to login as someone else.
  243.      * first make sure that we are root. */
  244.     if (amiga_seteuid (0) != -1)
  245.     {
  246.       struct muUserInfo *ui;
  247.  
  248.       if (ui = muAllocUserInfo ())
  249.       {
  250.     ui->uid = u;
  251.     if (muGetUserInfo (ui, muKeyType_uid))
  252.     {
  253.       tags[0] = muT_UserID;
  254.       tags[1] = (ULONG) ui->UserID;
  255.       tags[2] = muT_NoLog;
  256.       tags[3] = TRUE;
  257.       tags[4] = TAG_END;
  258.       res = (muLoginA (tags) ? 0 : -1);
  259.     }
  260.     muFreeUserInfo (ui);
  261.       }
  262.     }
  263.     return res;
  264.   }
  265.   /* MultiUser is not installed so use dummy
  266.    * usergroup.library call.
  267.    */
  268. #undef seteuid
  269.   return (seteuid (u));
  270. }
  271.  
  272. /*
  273.  * Simulate Unix seteuid() call with MultiUser.
  274.  * You have to be logged in as root initially for this
  275.  * routine to work (after that it correctly keeps track
  276.  * of the user).
  277.  */
  278. int
  279. amiga_setegid (int g)
  280. {
  281.   /* We can't set another group under
  282.    * MultiUser so we fail.
  283.    */
  284.   if (muBase)
  285.     return -1;
  286.   /* MultiUser is not installed so use dummy
  287.    * usergroup.library call.
  288.    */
  289. #undef setegid
  290.   return (setegid (g));
  291. }
  292.  
  293.  
  294. /*
  295.  * Simulate Unix getpwnam() call with MultiUser.
  296.  */
  297.  
  298. static struct passwd p;
  299. char dummypas[] = "";
  300.  
  301. struct passwd *
  302. amiga_getpwnam (char *name)
  303. {
  304.   if (muBase)
  305.   {
  306.     struct muUserInfo *ui;
  307.     BOOL ok = FALSE;
  308.  
  309.     if (ui = muAllocUserInfo ())
  310.     {
  311.       strcpy (ui->UserID, name);
  312.       if (muGetUserInfo (ui, muKeyType_UserID))
  313.       {
  314.     ok = TRUE;
  315.     p.pw_uid = ui->uid;
  316.     p.pw_gid = ui->gid;
  317.     if (p.pw_name)
  318.       free (p.pw_name);
  319.     if (p.pw_name = malloc (strlen (ui->UserID) + 1))
  320.       strcpy (p.pw_name, ui->UserID);
  321.     else
  322.       ok = FALSE;
  323.     p.pw_passwd = "";
  324.     if (p.pw_gecos)
  325.       free (p.pw_gecos);
  326.     if (p.pw_gecos = malloc (strlen (ui->UserName) + 1))
  327.       strcpy (p.pw_gecos, ui->UserName);
  328.     else
  329.       ok = FALSE;
  330.     if (p.pw_dir)
  331.       free (p.pw_dir);
  332.     if (p.pw_dir = malloc (strlen (ui->HomeDir) + 1))
  333.       strcpy (p.pw_dir, ui->HomeDir);
  334.     else
  335.       ok = FALSE;
  336.     if (p.pw_shell)
  337.       free (p.pw_shell);
  338.     if (p.pw_shell = malloc (strlen (ui->Shell) + 1))
  339.       strcpy (p.pw_shell, ui->Shell);
  340.     else
  341.       ok = FALSE;
  342.       }
  343.       muFreeUserInfo (ui);
  344.     }
  345.     if (!ok)
  346.       return (NULL);
  347.     return (&p);
  348.   }
  349. #undef getpwnam
  350.   return (getpwnam (name));
  351. }
  352.  
  353. /*
  354.  * Simulate Unix getgrnam() call with MultiUser.
  355.  */
  356.  
  357. static struct group g;
  358.  
  359. struct group *
  360. amiga_getgrnam (char *name)
  361. {
  362.   if (muBase)
  363.   {
  364.     struct muGroupInfo *gi;
  365.     BOOL ok = FALSE;
  366.  
  367.     if (gi = muAllocGroupInfo ())
  368.     {
  369.       strcpy (gi->GroupID, name);
  370.       if (muGetGroupInfo (gi, muKeyType_GroupID))
  371.       {
  372.     static char *dummy_memb = NULL;
  373.  
  374.     ok = TRUE;
  375.     g.gr_gid = gi->gid;
  376.     if (g.gr_name)
  377.       free (g.gr_name);
  378.     if (g.gr_name = malloc (strlen (gi->GroupID) + 1))
  379.       strcpy (g.gr_name, gi->GroupID);
  380.     else
  381.       ok = FALSE;
  382.     g.gr_passwd = "";
  383.     g.gr_mem = &dummy_memb;
  384.       }
  385.       muFreeGroupInfo (gi);
  386.     }
  387.     if (!ok)
  388.       return (NULL);
  389.     return (&g);
  390.   }
  391. #undef getgrnam
  392.   return (getgrnam (name));
  393. }
  394.  
  395. /*
  396.  * Simulate Unix umask() call with MultiUser.
  397.  */
  398.  
  399. const static BYTE abits[8] =
  400. {
  401.   0, 0x2, 0x5, 0x7, 0x8, 0xA, 0xD, 0xF,
  402. };
  403.  
  404. const static UBYTE ubits[16] =
  405. {
  406.   0, 2, 1, 3, 2, 2, 3, 3,
  407.   4, 6, 5, 7, 6, 6, 7, 7,
  408. };
  409.  
  410. ULONG
  411. U2A_prot (mode_t mode)
  412. {
  413.   return ((abits[mode & 7] << FIBB_OTR_DELETE) |
  414.       (abits[(mode >> 3) & 7] << FIBB_GRP_DELETE) |
  415.       (abits[(mode >> 6) & 7] ^ 0xf));
  416. }
  417.  
  418. mode_t
  419. A2U_prot (ULONG mode)
  420. {
  421.   return ((ubits[(mode ^ 0xf) & 0xf] << 6) |
  422.       (ubits[((mode ^ 0xf) >> FIBB_GRP_DELETE) & 0xf] << 3) |
  423.       (ubits[((mode ^ 0xf) >> FIBB_OTR_DELETE) & 0xf]));
  424. }
  425.  
  426. mode_t
  427. amiga_umask (mode_t m)
  428. {
  429.   if (muBase)
  430.   {
  431.     ULONG oldmask;
  432.  
  433.     oldmask = muGetDefProtection (NULL);
  434.     muSetDefProtection (muT_DefProtection, U2A_prot (m), TAG_END);
  435.     return (A2U_prot (oldmask));
  436.   }
  437. #undef umask
  438.   return (umask (m));
  439. }
  440.  
  441. mode_t
  442. amiga_getumask (void)
  443. {
  444.   if (muBase)
  445.     return (A2U_prot (muGetDefProtection (NULL)));
  446. #undef getumask
  447.   return (getumask ());
  448. }
  449.  
  450. /* dummy stub function for compatibility with original source */
  451. FILE *
  452. ftpd_popen (char *program, char *type, int closestderr)
  453. {
  454.   return (popen (program, type));
  455. }
  456.  
  457. /* dummy stub function for compatibility with original source */
  458. void
  459. ftpd_pclose (FILE * iop)
  460. {
  461.   pclose (iop);
  462. }
  463.  
  464. /*
  465.  * This is a stub function which is called when
  466.  * the SIGINT signal arrives. It checks if maybe
  467.  * this SIGINT is a SIGALRM and executes the
  468.  * appropriate function.
  469.  */
  470. void (*intfunc) (int) = NULL;
  471. void (*alrmfunc) (int) = NULL;
  472. BOOL isalrm = FALSE;
  473.  
  474. void
  475. amiga_sigalrm (int signum)
  476. {
  477. #undef signal
  478.   signal (SIGINT, amiga_sigalrm);
  479.   if (isalrm)            /* Did we really get a SIGALRM? */
  480.   {
  481.     isalrm = FALSE;
  482.     (*alrmfunc) (SIGALRM);    /* Yes, execute SIGALRM function */
  483.   }
  484.   else
  485.     (*intfunc) (SIGINT);    /* No, it was a standard ctrl-c */
  486. }
  487.  
  488. /*
  489.  * This is my implementation of the Unix alarm() function.
  490.  * Is kind of a hack, because when the time expires it sends
  491.  * a break signal (control-c) to itself, the break routine
  492.  * then notices that it was called from an alarm() and
  493.  * executes the proper code. A hack, but it works :-)
  494.  */
  495. struct Task *ThisTask;
  496. struct MsgPort *TimerPort = NULL;
  497. struct timerequest *TimerIO = NULL;
  498. struct Interrupt *TimerInterrupt = NULL;
  499. BOOL deviceopen = FALSE, alarmon = FALSE;
  500.  
  501. void __saveds __interrupt
  502. IntFunc (void)
  503. {
  504.   struct Message *msg;
  505.  
  506.   if ((msg = GetMsg (TimerPort)) && alarmon)
  507.   {
  508.     isalrm = TRUE;
  509.     Signal (ThisTask, SIGBREAKF_CTRL_C);
  510.   }
  511. }
  512.  
  513. void
  514. cleanup_alarm (void)
  515. {
  516.   if (TimerIO)
  517.   {
  518.     alarmon = FALSE;
  519.  
  520.     if (!CheckIO (TimerIO))
  521.     {
  522.       AbortIO (TimerIO);
  523.       WaitIO (TimerIO);
  524.     }
  525.   }
  526.   if (deviceopen)
  527.   {
  528.     CloseDevice (TimerIO);
  529.     deviceopen = FALSE;
  530.   }
  531.   if (TimerIO)
  532.   {
  533.     DeleteExtIO (TimerIO);
  534.     TimerIO = NULL;
  535.   }
  536.   if (TimerPort)
  537.   {
  538.     FreeVec (TimerPort);
  539.     TimerPort = NULL;
  540.   }
  541.   if (TimerInterrupt)
  542.   {
  543.     FreeVec (TimerInterrupt);
  544.     TimerInterrupt = NULL;
  545.   }
  546. }
  547.  
  548. int
  549. alarm (int t)
  550. {
  551.   if (t == 0)
  552.   {
  553.     alarmon = FALSE;
  554.  
  555.     /* delete previous timer request */
  556.     if (TimerIO)
  557.     {
  558.       if (!CheckIO (TimerIO))
  559.       {
  560.     AbortIO (TimerIO);
  561.     WaitIO (TimerIO);
  562.       }
  563.     }
  564.   }
  565.   else
  566.   {
  567.     ThisTask = FindTask (NULL);
  568.     if (!TimerInterrupt)
  569.     {
  570.       if (TimerInterrupt = AllocVec (sizeof (struct Interrupt), MEMF_CLEAR))
  571.       {
  572.     TimerInterrupt->is_Node.ln_Type = NT_INTERRUPT;
  573.     TimerInterrupt->is_Code = &IntFunc;
  574.       }
  575.     }
  576.  
  577.     if (TimerInterrupt && !TimerPort)
  578.     {
  579.       if (TimerPort = AllocVec (sizeof (struct MsgPort), MEMF_CLEAR))
  580.       {
  581.     TimerPort->mp_Node.ln_Type = NT_MSGPORT;
  582.     TimerPort->mp_Flags = PA_SOFTINT;    /* cause a software interrupt when signal arrives */
  583.     TimerPort->mp_SoftInt = TimerInterrupt;
  584.     NewList (&(TimerPort->mp_MsgList));
  585.       }
  586.     }
  587.  
  588.     if (TimerPort && !TimerIO)
  589.       TimerIO = (struct timerequest *) CreateExtIO (TimerPort, sizeof (struct timerequest));
  590.  
  591.     if (TimerPort && TimerIO && !deviceopen)
  592.     {
  593.       deviceopen = (!OpenDevice (TIMERNAME, UNIT_VBLANK, (struct IORequest *) TimerIO, 0));
  594.       if (deviceopen)
  595.     atexit (cleanup_alarm);
  596.     }
  597.  
  598.     if (deviceopen)
  599.     {
  600.       alarmon = FALSE;
  601.       if (!CheckIO (TimerIO))
  602.       {
  603.     AbortIO (TimerIO);
  604.     WaitIO (TimerIO);
  605.       }
  606.       TimerIO->tr_node.io_Command = TR_ADDREQUEST;
  607.       TimerIO->tr_time.tv_secs = t;
  608.       TimerIO->tr_time.tv_micro = 0;
  609.       alarmon = TRUE;
  610.       BeginIO ((struct IORequest *) TimerIO);
  611.     }
  612.     else
  613.       cleanup_alarm ();
  614.   }
  615. }
  616.  
  617. /*
  618.  * This is a new signal() function that also knows
  619.  * about SIGALRM (it installs SIGALRM as SIGINT with
  620.  * a special handler that knows about both SIGALRM and
  621.  * SIGINT).
  622.  */
  623. void
  624.   (*amiga_signal (int signum, void (*sigfunc) (int))) (int)
  625. {
  626.   void (*oldfunc) (int) = NULL;
  627.   if (signum == SIGALRM || signum == SIGINT)
  628.   {
  629.     if (!intfunc)
  630.       intfunc = signal (SIGINT, amiga_sigalrm);
  631.  
  632.     if (signum == SIGINT)
  633.     {
  634.       oldfunc = intfunc;
  635.       intfunc = sigfunc;
  636.     }
  637.     else
  638.     {
  639.       oldfunc = alrmfunc;
  640.       alrmfunc = sigfunc;
  641.     }
  642.   }
  643.   else
  644.     return (signal (signum, sigfunc));
  645.   return oldfunc;
  646. }
  647.  
  648. #ifdef SETPROCTITLE
  649. /* Sets name of currently running program. */
  650. void
  651. setproctitle (const char *fmt,...)
  652. {
  653.   va_list args;
  654.   char *text;
  655.  
  656.   if (text = malloc (BUFSIZ))
  657.   {
  658.     char *newfmt;
  659.  
  660.     if (newfmt = malloc (strlen (fmt) + sizeof ("ftpd: ")))
  661.     {
  662.       sprintf (newfmt, "ftpd: %s", fmt);
  663.       va_start (args, fmt);
  664.       vsprintf (text, newfmt, args);
  665.       SetProgramName (text);
  666.       va_end (args);
  667.       free (newfmt);
  668.     }
  669.     else
  670.       SetProgramName ("ftpd");
  671.     free (text);
  672.   }
  673.   else
  674.     SetProgramName ("ftpd");
  675. }
  676. #endif
  677.